/*********************************************************************
 * Módulo 3. Tutorial de desarrollo con NME. Bucle de juego
 * Programación Multimedia y Juegos
 * Autor: David Vallejo Fernández    david.vallejo@tegnix.com
 * Autor: Carlos González Morcillo   carlos.gonzalez@tegnix.com
 *
 * You can redistribute and/or modify this file under the terms of the
 * GNU General Public License ad published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * and later version. See <http://www.gnu.org/licenses/>.
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  
 *********************************************************************/

package;

import com.eclecticdesignstudio.motion.Actuate;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import nme.events.KeyboardEvent;
import nme.events.MouseEvent;
import flash.Lib;

class GameManager {

  // Variable estática para implementar Singleton.
  public static var _instance:GameManager;
  // Pila de estados.
  private var _states:Array<GameState>;

  private function new () { 
    _states = new Array<GameState>();
  }

  // Patrón Singleton.
  public static function getInstance() : GameManager {
    if (GameManager._instance == null)
      GameManager._instance = new GameManager();
    return GameManager._instance;
  }

  public function start (state:GameState) : Void {
    Lib.current.stage.align = StageAlign.TOP_LEFT;
    Lib.current.stage.scaleMode = StageScaleMode.NO_SCALE;

    // Registro de event listeners.
    // Permiten asociar evento y código de tratamiento.
    Lib.current.stage.addEventListener(Event.ENTER_FRAME, frameStarted);
    Lib.current.stage.addEventListener(MouseEvent.CLICK, mouseClicked);
    Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
    Lib.current.stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);

    // Transición al estado inicial.
    changeState(state);
  }

  public function changeState (state:GameState) : Void { 
    // Limpieza del estado actual.
    if (_states.length > 0) {
      _states.pop().exit();
    }
    
    // Transición al nuevo estado.
    _states.push(state);
    state.enter();
  }

  public function pushState (state:GameState) : Void { 
    // Pause del estado actual.
    if (_states.length > 0) {
      _states[_states.length -1].pause();
    }

    // Transición al nuevo estado.
    _states.push(state);
    state.enter();
  }

  public function popState () : Void {  
    // Limpieza del estado actual.
    if (_states.length > 0) {
      _states.pop().exit();
    }

    // Reanudación del estado anterior.
    _states[_states.length -1].resume();
  }

  // Gestión de eventos de teclado y ratón.
  // Se delega en el estado actual (cima de la pila).

  public function keyPressed (event:KeyboardEvent) : Void {
    _states[_states.length -1].keyPressed(event);
  }

  public function keyReleased (event:KeyboardEvent) : Void {
    _states[_states.length -1].keyReleased(event);
  }

  public function mouseClicked (event:MouseEvent) : Void { 
    _states[_states.length -1].mouseClicked(event);
  } 

  // Gestión básica para la gestión
  // de eventos antes y después de renderizar un frame.

  public function frameStarted (event:Event) : Void { 
    _states[_states.length -1].frameStarted(event);
  }

  public function frameEnded (event:Event) : Void { 
    _states[_states.length -1].frameEnded(event);
  }

}